package art_of_java_concurrent_programming.final_future;

/**
 * 对于final域，编译器和处理器要遵守两个重排序规则。
 * 1）在构造函数内对一个final域的写入，与随后把这个被构造对象的引用赋值给一个引用变量，
 * 这两个操作之间不能重排序。
 * 2）初次读一个包含final域的对象的引用，与随后初次读这个final域，
 * 这两个操作之间不能重排序。
 *
 * 写final域的重排序规则
 * 1）JMM禁止编译器把final域的写重排序到构造函数之外。
 * 2）编译器会在final域的写之后，构造函数return之前，插入一个StoreStore屏障。
 * 这个屏障禁止处理器把final域的写重排序到构造函数之外。
 *
 * 读final域的重排序规则
 * 在一个线程中，初次读对象引用与初次读该对象包含的final域，
 * JMM禁止处理器重排序这两个操作（注意，这个规则仅仅针对处理器）。
 *
 */
public class FinalExample {
    // 普通变量
    int i;
    // final变量
    final int j;
    static FinalExample obj;

    public FinalExample() { // 构造函数
        i = 1; // 写普通域
        j = 2; // 写final域
    }

    public static void writer() { // 写线程A执行
        obj = new FinalExample();
    }

    public static void reader() { // 读线程B执行
        FinalExample object = obj; // 读对象引用
        int a = object.i; // 读普通域
        int b = object.j; // 读final域
    }
}